<template>
    <div class="home">
        <!-- 左侧模块菜单 -->
        <div class="menu-bar">
            <h2>模块列表</h2>
            <!-- 模块列表 -->
            <div class="menu-list">
                <div v-for="item in moduleList" :key="item.id" draggable="true" @dragstart="handleDragStart($event, item)">
                    <p>{{ item.name }}</p>
                </div>
            </div>
        </div>
        <!-- 画布部分 -->
        <div class="canvas-card">
            <div id="container" @dragover="dragoverDiv" @drop="handleDrag"></div>
        </div>
    </div>
</template>

<script>
import { Graph } from '@antv/x6'
import Tools from './graphTools.js'
export default {
    data() {
        return {
            moduleList: [
                {
                    id: 1,
                    name: '开始模块',
                    type: 'initial' // 初始模块(用于区分样式)
                },
                {
                    id: 2,
                    name: '结束模块',
                    type: 'initial'
                },
                {
                    id: 3,
                    name: '逻辑模块1',
                    type: 'logic' // 逻辑模块(用于区分样式)
                },
                {
                    id: 4,
                    name: '逻辑模块2',
                    type: 'logic'
                }
            ], // 列表可拖动模块
            graph: null, // 画布实例对象
            curSelectNode: null, // 当前选中的节点
            // 拖动时候携带的业务数据对象
            itemObj: {}
        }
    },
    mounted() {
        this.initGraph()
    },
    methods: {
        // 初始化流程图画布
        initGraph() {
            let container = document.getElementById('container')
            this.graph = new Graph({
                container: container, // 画布容器
                width: container.offsetWidth, // 画布宽
                height: container.offsetHeight, // 画布高
                background: false, // 背景（透明）
                snapline: true, // 对齐线
                // 配置连线规则
                connecting: {
                    snap: true, // 自动吸附
                    allowBlank: false, //是否允许连接到画布空白位置的点
                    allowMulti: false, //是否允许在相同的起始节点和终止之间创建多条边
                    allowLoop: false, //是否允许创建循环连线，即边的起始节点和终止节点为同一节点
                    highlight: true, //拖动边时，是否高亮显示所有可用的节点
                    validateEdge({ edge, type, previous }) {
                        // 连线时设置折线
                        edge.setRouter({
                            name: 'er',
                        })
                        // 设置连线样式
                        edge.setAttrs({
                            line: {
                                stroke: '#275da3',
                                strokeWidth: 1,
                            },
                        })
                        return true
                    },
                },
                panning: {
                    enabled: true,
                },
                mousewheel: {
                    enabled: true, // 支持滚动放大缩小
                },
                grid: {
                    type: 'mesh',
                    size: 20,      // 网格大小 10px
                    visible: true, // 渲染网格背景
                    args: {
                        color: '#eeeeee', // 网格线/点颜色
                        thickness: 2,     // 网格线宽度/网格点大小
                    },
                },
            })
            this.nodeAddEvent()
        },
        // 生成节点函数
        addHandleNode(x, y, id, name, type) {
            type === 'initial'
                ?
                this.graph.addNode(Tools.initInitialNode(x, y, id, name, type))
                :
                this.graph.addNode(Tools.initLogicNode(x, y, id, name, type))
        },
        // 注册画布事件
        nodeAddEvent() {
            // 节点绑定点击事件
            this.graph.on('node:click', ({ e, x, y, node, view }) => {
                // 判断是否有选中过节点
                if (this.curSelectNode) {
                    // 移除选中状态
                    this.curSelectNode.removeTools()
                    // 判断两次选中节点是否相同
                    if (this.curSelectNode !== node) {
                        node.addTools([{
                            name: 'boundary',
                            args: {
                                attrs: {
                                    fill: '#16B8AA',
                                    stroke: '#2F80EB',
                                    strokeWidth: 1,
                                    fillOpacity: 0.1
                                }
                            }
                        }, {
                            name: 'button-remove',
                            args: {
                                x: '100%',
                                y: 0,
                                offset: {
                                    x: 0,
                                    y: 0
                                }
                            }
                        }])
                        this.curSelectNode = node
                    } else {
                        this.curSelectNode = null
                    }
                } else {
                    this.curSelectNode = node
                    node.addTools([{
                        name: 'boundary',
                        args: {
                            attrs: {
                                fill: '#16B8AA',
                                stroke: '#2F80EB',
                                strokeWidth: 1,
                                fillOpacity: 0.1
                            }
                        }
                    }, {
                        // 删除节点
                        name: 'button-remove',
                        args: {
                            x: '100%',
                            y: 0,
                            offset: {
                                x: 0,
                                y: 0
                            }
                        }
                    }])
                }
            })
            // 连线绑定悬浮事件
            this.graph.on('cell:mouseenter', ({ cell }) => {
                if (cell.shape == 'edge') {
                    cell.addTools([
                        {
                            name: 'button-remove',
                            args: {
                                x: '100%',
                                y: 0,
                                offset: {
                                    x: 0,
                                    y: 0
                                },
                            },
                        }])
                    cell.setAttrs({
                        line: {
                            stroke: '#409EFF',
                        },
                    })
                    cell.zIndex = 99
                }
            })
            this.graph.on('cell:mouseleave', ({ cell }) => {
                if (cell.shape === 'edge') {
                    cell.removeTools()
                    cell.setAttrs({
                        line: {
                            stroke: '#275da3',
                        },
                    })
                    cell.zIndex = 1
                }
            })
        },
        // 拖动后松开鼠标触发事件
        handleDragStart(e, item) {
            this.itemObj = item;
        },
        // 接收拖动过来的元素释放鼠标之后触发， 拖拽元素至画布区域。
        handleDrag(e) {
            this.addHandleNode(e.layerX, e.layerY, new Date().getTime(), this.itemObj.name, this.itemObj.type)
        },
        // 拖动的时候阻止默认事件
        dragoverDiv(ev) {
            ev.preventDefault();
        },
    },
}
</script>


<style lang="less" scoped>
.home {
  width: 100%;
  height: 100wh;
  display: flex;
  padding: 20px;
  box-sizing: border-box;
  background: #eaeaea;
  > div {
    background: #ffffff;
    border-radius: 5px;
  }
  // 模块列表部分
  .menu-bar {
    width: 200px;
    height: 100%;
    margin-right: 20px;
    display: flex;
    flex-direction: column;
    h2 {
      width: 100%;
      font-size: 20px;
      padding: 10px;
      box-sizing: border-box;
      margin: 0;
    }
    .menu-list {
      height: 0;
      flex: 1;
      overflow: auto;
      padding: 0 10px;
      box-sizing: border-box;
      > div {
        border: 2px dashed #eaeaea;
        margin-bottom: 10px;
        border-radius: 5px;
        padding: 0 10px;
        box-sizing: border-box;
        cursor: pointer;
      }
    }
  }
  // 画布部分
  .canvas-card {
    width: 0;
    flex: 1;
    height: 100%;
    padding: 20px;
    box-sizing: border-box;
    > div {
      width: 100%;
      height: 100%;
      border: 2px dashed #eaeaea;
    }
  }
}
</style>
<style lang="less">
// 其中节点样式加到没有scoped包裹的style标签中，否则样式不生效
// 初始节点样式
.custom_node_initial {
  width: 100%;
  height: 100%;
  display: flex;
  border-radius: 3px;
  background: rgba(22, 184, 169, 0.6);
  flex-direction: column;
  overflow: hidden;
  > div {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2px;
    box-sizing: border-box;
    border: 2px solid rgba(47, 128, 235, 0.6);
    i {
      line-height: 22px;
      font-size: 18px;
      color: #ffffff;
      display: flex;
      align-items: center;
      margin-right: 5px;
      justify-content: center;
      font-style: normal;
    }
    p {
      color: #ffffff;
      font-size: 16px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
}
// 逻辑节点样式
.custom_node_logic {
  width: 100%;
  height: 100%;
  display: flex;
  background: rgba(47, 128, 235, 0.5);
  flex-direction: column;
  overflow: hidden;
  border-radius: 5px;
  > div {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2px;
    box-sizing: border-box;
    border: 2px solid rgba(22, 184, 169, 0.5);
    border-radius: 5px;
    line-height: 22px;
    i {
      line-height: 22px;
      font-size: 18px;
      color: #b5cde9;
      margin-right: 5px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-style: normal;
    }
    p {
      color: #ffffff;
      font-size: 14px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
}
</style>
